package com.yunwushanhe.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yunwushanhe.bean.req.*;
import com.yunwushanhe.bean.ret.ResponseResult;
import com.yunwushanhe.bean.vo.*;
import com.yunwushanhe.constant.RedisConstant;
import com.yunwushanhe.entity.LoginUser;
import com.yunwushanhe.entity.User;
import com.yunwushanhe.entity.UserRole;
import com.yunwushanhe.enums.AppHttpCodeEnum;
import com.yunwushanhe.mapper.AdminUserMapper;
import com.yunwushanhe.mapper.UserMapper;
import com.yunwushanhe.service.AdminUserService;
import com.yunwushanhe.service.RoleService;
import com.yunwushanhe.service.UserRoleService;
import com.yunwushanhe.util.BeanCopyUtil;
import com.yunwushanhe.util.JwtUtil;
import com.yunwushanhe.util.RedisCache;
import com.yunwushanhe.util.UserContextUtil;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author 抬头看看天
 * @Date 2023-08-22  16:46:25
 */
@Service
public class AdminUserServiceImpl extends ServiceImpl<UserMapper, User> implements AdminUserService {

    @Resource
    private RedisCache redisCache;
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private UserRoleService userRoleService;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private RoleService roleService;

    @Override
    public ResponseResult<Object> adminLogin(UserLoginReq userLoginReq) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userLoginReq.getUserName(), userLoginReq.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken); // 会调用 UserDetailsServiceImpl 这个里面的方法
        //判断是否认证通过
        if(ObjectUtils.isEmpty(authenticate)){
            throw new RuntimeException("用户名或密码错误"); // 这个异常会交给全局异常处理器处理
        }
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String userId = loginUser.getUser().getId().toString();
        String token = JwtUtil.createJWT(userId);
        //把信息存入redis中
        redisCache.setCacheObject(RedisConstant.LOGIN_ADMIN_USERINFO_KEY +":"+userId,loginUser);

        HashMap<String, String> map = new HashMap<>();
        map.put("token",token);
        return ResponseResult.ok(map);
    }

    @Override
    public ResponseResult<Object> adminLogout() {
        Long userId = UserContextUtil.getUserId();
        redisCache.deleteObject(RedisConstant.LOGIN_ADMIN_USERINFO_KEY+":"+userId);
        return ResponseResult.ok();
    }

    @Override
    public ResponseResult<PageVO<List<UserPageListVO>>> getUserPageList(UserPageListReq userPageListReq) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(userPageListReq.getUserName()),User::getUserName,userPageListReq.getUserName());
        queryWrapper.like(StringUtils.hasText(userPageListReq.getPhonenumber()),User::getPhonenumber,userPageListReq.getPhonenumber());
        queryWrapper.eq(StringUtils.hasText(userPageListReq.getStatus()),User::getStatus,userPageListReq.getStatus());

        Page<User> userPage = new Page<>();
        userPage.setCurrent(userPageListReq.getPageNum());
        userPage.setSize(userPageListReq.getPageSize());

        page(userPage,queryWrapper);
        List<UserPageListVO> userPageListVOList = BeanCopyUtil.copyBeanList(userPage.getRecords(), UserPageListVO.class);
        PageVO<List<UserPageListVO>> pageVO = new PageVO<>(userPageListVOList, userPage.getTotal());
        return ResponseResult.ok(pageVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Object> addUser(UserAddReq userAddReq) {
        if(!StringUtils.hasText(userAddReq.getUserName())){
            return ResponseResult.error(AppHttpCodeEnum.USERNAME_NOT_NULL);
        }

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName,userAddReq.getUserName());
        if(getOne(queryWrapper) != null){
            return ResponseResult.error(AppHttpCodeEnum.USERNAME_EXIST);
        }
        queryWrapper.clear();
        queryWrapper.eq(User::getPhonenumber,userAddReq.getPhonenumber());
        if(getOne(queryWrapper) != null){
            return ResponseResult.error(AppHttpCodeEnum.PHONE_NUMBER_EXIST);
        }
        queryWrapper.clear();
        queryWrapper.eq(User::getEmail,userAddReq.getEmail());
        if(getOne(queryWrapper) != null){
            return ResponseResult.error(AppHttpCodeEnum.EMAIL_EXIST);
        }

        User user = BeanCopyUtil.copyBean(userAddReq, User.class);
        String password = passwordEncoder.encode(user.getPassword());
        user.setPassword(password);
        save(user);

        Long userId = user.getId();
        List<String> roleIdList = userAddReq.getRoleIds();
        List<UserRole> userRoleList = roleIdList.stream()
                .map(roleId -> new UserRole(userId, Long.valueOf(roleId)))
                .collect(Collectors.toList());

        userRoleService.saveBatch(userRoleList);
        return ResponseResult.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Object> deleteUserById(String id) {
        String[] arrayId = id.split(",");
        ArrayList<Long> listId = new ArrayList<>();
        for (String s : arrayId) {
            listId.add(Long.valueOf(s));
        }
        removeByIds(listId);

        // 把关系表中的关系一并删除了
        LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(UserRole::getUserId,listId);
        userRoleService.remove(queryWrapper);

        return ResponseResult.ok();
    }

    @Override
    public ResponseResult<UserUpdateVO> getUserById(Long id) {
        LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserRole::getUserId,id);
        List<String> roleIdList = userRoleService.list(queryWrapper).stream()
                .map(userRole -> userRole.getRoleId().toString())
                .collect(Collectors.toList());

        List<RoleListVO> roleList = roleService.getRoleList().getData();

        User user = getById(id);
        UserUpdateInfoVO userUpdateInfoVO = BeanCopyUtil.copyBean(user, UserUpdateInfoVO.class);

        return ResponseResult.ok(new UserUpdateVO(roleIdList,roleList,userUpdateInfoVO));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Object> updateUserById(UserUpdateReq userUpdateReq) {
        HashMap<String, Object> eqMap = new HashMap<>();
        eqMap.put("id",userUpdateReq.getId());

        ArrayList<String> ignoreFieldList = new ArrayList<>();
        ignoreFieldList.add("roleIds");

        UpdateWrapper<User> updateWrapper =
                BeanCopyUtil.ignoreNullUpdateWrapper(eqMap, userUpdateReq, User.class, ignoreFieldList);
        update(updateWrapper);

        LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(UserRole::getUserId,userUpdateReq.getId());
        userRoleService.remove(queryWrapper);
        List<UserRole> userRoleList = userUpdateReq.getRoleIds().stream()
                .map(roleId -> new UserRole(userUpdateReq.getId(), Long.valueOf(roleId)))
                .collect(Collectors.toList());
        userRoleService.saveBatch(userRoleList);
        return ResponseResult.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Object> changeUserStatus(UserStatusUpdateReq userStatusUpdateReq) {
        try {
            HashMap<String, Object> eqMap =
                    BeanCopyUtil.eqMap("id", userStatusUpdateReq.getUserId());
            ArrayList<String> ignoreFieldList =
                    BeanCopyUtil.ignoreFieldList("userId");
            UpdateWrapper<User> updateWrapper =
                    BeanCopyUtil.ignoreNullUpdateWrapper(eqMap, userStatusUpdateReq, User.class,ignoreFieldList);
            update(updateWrapper);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return ResponseResult.ok();
    }
}
